/**
 * Created by cqb32_000 on 2016-12-18.
 */

var jsts = require("jsts");
var wktreader = new jsts.io.WKTReader();
var Cesium = require("cesium");
var ellipsoid = Cesium.Ellipsoid.WGS84;
var moment = require("moment");
var config = require("../config");
var Utils = require(__dirname+"/Utils");
var hasha = require('hasha');
var redis = require('redis');

var RDS_PORT = 6379,        //端口号
    RDS_HOST = '127.0.1.1',    //服务器IP
    RDS_PWD = '123456',
    RDS_OPTS = {},            //设置项
    client = redis.createClient(RDS_PORT,RDS_HOST,RDS_OPTS);


var Worker = function(options){
    this.startTime = moment(options.startTime);
    this.endTime = moment(this.startTime);
    this.endTime.add(1, "days");

    this.satellites = options.sats;
    this.mission = options.mis;
    this.step_seconds = 20;
    this.min_step_seconds = 0.1;

    try {
        this.getOneDayOpportunities();
    }catch(e){
        console.trace(e);
    }
};

Worker.prototype = {
    getOneDayOpportunities: function(){
        if(!this.satellites){
            return ;
        }
        var alltimes = [];
        var ps = [];
        for(var i in this.satellites){
            var sat = this.satellites[i];
            var tle = hasha(sat.sat_tle);
            var key = this.mission.mis_id+"_"+this.mission.mis_order_modifytime+":"+sat.sen_id+":"+tle+":"+this.startTime.format("YYYY-MM-DD");

            var p = new Promise((resolve, reject)=>{
                this.getTimesByKey(key, (times)=>{
                    if(times){
                        times = JSON.parse(times);
                        times = times.map((time)=>{
                            return {
                                start: Cesium.JulianDate.fromDate(new Date(time.start)),
                                end: Cesium.JulianDate.fromDate(new Date(time.end)),
                                sat: sat,
                                mis: this.mission
                            }
                        });
                    }else{
                        times = this.getOneDayOneSatOpportunities(sat);
                        this.storeTimes(key, times);
                    }
                    alltimes = alltimes.concat(times);
                    resolve(times);
                });
            });
            ps.push(p);
        }

        Promise.all(ps).then((ret)=>{
            alltimes.sort(function(t1, t2){
                return Cesium.JulianDate.compare(t1.start, t2.start);
            });

            process.send(alltimes);
        });
    },

    getTimesByKey: function(key, callback){
        client.get(key, function(err, times){
            callback ? callback(times) : false;
        });
    },

    storeTimes: function(key, times){
        if(times) {
            var ret = times.map(function (time) {
                return {
                    start: moment(Cesium.JulianDate.toDate(time.start)).format("YYYY-MM-DD HH:mm:ss.SSS"),
                    end: moment(Cesium.JulianDate.toDate(time.end)).format("YYYY-MM-DD HH:mm:ss.SSS")
                }
            });
            client.set(key, JSON.stringify(ret));
            client.expire(key, config.REDISEXP);
        }
    },

    getOneDayOneSatOpportunities: function(sat){
        var times = this.getStripeTimes(sat);
        times.forEach((time)=>{
            time.sat = sat;
            time.mis = this.mission;
        });
        return times;
    },

    getStripeTimes: function(sat){
        var st = Cesium.JulianDate.fromDate(this.startTime.toDate());
        var et = Cesium.JulianDate.fromDate(this.endTime.toDate());

        var wkt = this.mission.mis_plot;
        var misgeom = wktreader.read(wkt);
        return this.getTimes(sat, st, et, misgeom);
    },

    /**
     * 计算时间段
     * @param sat
     * @param st
     * @param et
     * @param plot
     * @returns {Array}
     * @private
     */
    getTimes: function(sat, st, et, plot) {
        var julianDate, minutes;
        var allminutes = Cesium.JulianDate.secondsDifference(et, st) / Cesium.TimeConstants.SECONDS_PER_MINUTE;
        var step = this.step_seconds / Cesium.TimeConstants.SECONDS_PER_MINUTE;

        var times = [];
        var lastintersects = false;
        for (minutes = 0; minutes <= allminutes; minutes += step) {
            julianDate = Cesium.JulianDate.addMinutes(st, minutes, new Cesium.JulianDate());
            var pos = Utils.getPositionByTime(sat, julianDate);

            if(!this.isDayLight(pos, julianDate)){
                continue;
            }

            var nextpos = Utils.getPositionByTime(sat, Cesium.JulianDate.addMinutes(julianDate, step, new Cesium.JulianDate()));
            var lrpos = Utils.getMaxTiltPositions(sat, pos, sat.max_tilt);
            var lp1 = ellipsoid.cartesianToCartographic(lrpos[0]);
            var rp1 = ellipsoid.cartesianToCartographic(lrpos[1]);

            lrpos = Utils.getMaxTiltPositions(sat, nextpos, sat.max_tilt);
            var lp2 = ellipsoid.cartesianToCartographic(lrpos[0]);
            var rp2 = ellipsoid.cartesianToCartographic(lrpos[1]);

            var poly = [lp1, lp2, rp2, rp1];

            if (this.intersects(poly, plot)) {
                var lasttime = times.length ? times[times.length - 1] : null;
                if (lastintersects) {
                    lasttime.end = Cesium.JulianDate.addMinutes(julianDate, step, new Cesium.JulianDate());
                } else {
                    times.push({
                        start: julianDate.clone(),
                        end: Cesium.JulianDate.addMinutes(julianDate, step, new Cesium.JulianDate())
                    });
                }
                lastintersects = true;
            } else {
                lastintersects = false;
            }
        }

        // for (var i in times) {
        //     var time = times[i];
        //     time.start = this.optimize(sat, time.start, plot, true);
        //     time.end = this.optimize(sat, time.end, plot, false);
        //     time.range = Cesium.JulianDate.secondsDifference(time.end, time.start) / Cesium.TimeConstants.SECONDS_PER_MINUTE;
        //     var scenelength = sat.sen_scenelength / Cesium.TimeConstants.SECONDS_PER_MINUTE;
        //     var scenenum = parseInt(time.range / scenelength);
        //     if (time.range % scenelength != 0 || !scenenum) {
        //         scenenum += 1;
        //     }
        //     time.scenenum = scenenum;
        //     time.orbitnum = Utils.getOrbitnum(sat, time.start);
        // }

        return times;
    },

    /**
     * 是不是白天
     * @param pos
     * @param julianDate
     * @returns {boolean}
     */
    isDayLight: function(pos, julianDate){
        var date = Cesium.JulianDate.toDate(julianDate);
        var p = ellipsoid.cartesianToCartographic(pos);
        var solorinfo = Utils.calculateSolorAzEL(p, date);
        return solorinfo.ele > 0;
    },

    /**
     * 判断是否相交
     * @param geometry1
     * @param plot
     * @returns {boolean}
     */
    intersects: function(geometry1, plot) {
        var wkt1 = this.convertToWKT(geometry1);
        // console.log(wkt1);

        var geom1 = wktreader.read(wkt1);
        var geoms = this.splitPolygon(geom1);


        var intersects = false;
        geoms.forEach(function (geom) {
            if (geom.intersects(plot)) {
                intersects = true;
            }
        });

        return intersects;
    },
    /**
     * 将坐标转化为wkt
     * @param positions
     * @returns {Array}
     */
    convertToWKT: function(positions) {
        if (positions[0] != positions[positions.length - 1]) {
            positions.push(positions[0]);
        }
        var wkt = [];
        positions.forEach(function (position) {
            wkt.push(position.longitude * 180 / Math.PI + " " + position.latitude * 180 / Math.PI);
        });
        wkt = wkt.join(",");
        wkt = "POLYGON((" + wkt + "))";
        return wkt;
    },

    /**
     * 根据180度经线分割polygon
     * @param polygon
     * @returns {*[]}
     */
    splitPolygon: function(polygon) {
        var extent = polygon.computeEnvelopeInternal();
        var w = Math.abs(extent.maxx - extent.minx);
        if(w>180){
            var points = polygon.shell.points;
            var splitindexs = [];
            for (var i = 0; i < points.length - 1; i++) {
                if (points[i].x * points[i + 1].x < 0) {
                    if (Math.abs(points[i].x - points[i + 1].x) > 180) {
                        splitindexs.push(i);
                    }
                }
            }

            if (splitindexs.length) {
                var jsts = require("jsts");
                var factory = new jsts.geom.GeometryFactory();
                var index1 = splitindexs[0];
                var index2 = splitindexs[1];
                var polypos = points.splice(index1 + 1, index2 - index1);

                if (!polypos[0].equals(polypos[polypos.length - 1])) {
                    polypos.push(polypos[0]);
                }

                var linering1 = factory.createLinearRing(polypos);
                var poly1 = factory.createPolygon(linering1, null);
                var linering2 = factory.createLinearRing(points);
                var poly2 = factory.createPolygon(linering2, null);

                return [poly1, poly2];
            } else {
                return [polygon];
            }
        }else{
            return [polygon];
        }
    },

    /**
     * 精度优化
     * @param sat
     * @param start
     * @param wkt
     * @param isstart
     * @returns {*}
     */
    optimize: function(sat, start, plot, isstart) {
        var minstep = this.min_step_seconds / Cesium.TimeConstants.SECONDS_PER_MINUTE;
        var step = this.step_seconds / Cesium.TimeConstants.SECONDS_PER_MINUTE;
        var minutes, julianDate;

        var time = start;
        for (minutes = 0; minutes <= step;) {
            var delta = isstart ? 1 : -1;
            julianDate = Cesium.JulianDate.addMinutes(start, delta * minutes, new Cesium.JulianDate());

            var pos = Utils.getPositionByTime(sat, julianDate);
            var nextpos = Utils.getPositionByTime(sat, Cesium.JulianDate.addMinutes(julianDate, delta * minstep, new Cesium.JulianDate()));
            var lrpos = Utils.getMaxTiltPositions(sat, pos, sat.max_tilt);
            var halfpos = Utils.getMaxTiltPositions(sat, pos, sat.max_tilt/2);
            var lp1 = ellipsoid.cartesianToCartographic(lrpos[0]);
            var hlp1 = ellipsoid.cartesianToCartographic(halfpos[0]);
            var cp1 = ellipsoid.cartesianToCartographic(pos);
            var rp1 = ellipsoid.cartesianToCartographic(lrpos[1]);
            var hrp1 = ellipsoid.cartesianToCartographic(halfpos[1]);

            lrpos = Utils.getMaxTiltPositions(sat, nextpos, sat.max_tilt);
            var halfrpos = Utils.getMaxTiltPositions(sat, nextpos, sat.max_tilt/2);
            var lp2 = ellipsoid.cartesianToCartographic(lrpos[0]);
            var hlp2 = ellipsoid.cartesianToCartographic(halfrpos[0]);
            var cp2 = ellipsoid.cartesianToCartographic(nextpos);
            var rp2 = ellipsoid.cartesianToCartographic(lrpos[1]);
            var hrp2 = ellipsoid.cartesianToCartographic(halfrpos[1]);

            var poly = [lp1, lp2, hlp2, cp2, hrp2, rp2, rp1, hrp1, cp1, hlp1];

            if (this.intersects(poly, plot)) {
                time = julianDate.clone();
                break;
            }

            minutes = minutes + minstep;
        }

        return time;
    }
};



process.on("message", function(data){
    new Worker(data);
});